# _*_coding:utf-8_*_
import math
import os
import sys
import time

from ATS.instrumentDriver import InstCom as inst

workpath = os.getcwd()
sys.path.insert(0, os.path.dirname(workpath))

Func_Map = ["curr", "volt"]
Func_Map_R = ["volt", "curr"]
debug_mode = 0
OK = 0
COMP_OCCURED = 201


def commonsetup(**kwargs):
    # is_beep = kwargs.get("is_beep")
    is_rst = kwargs.get("is_rst")
    cmd_dict = {}
    # is_rst = 0
    if is_rst:
        for s in is_rst:
            cmd_str = "*rst"
            if not (s in cmd_dict):
                cmd_dict[s] = []
            cmd_dict[s].append(cmd_str)
    """
    if is_beep:
        for s in is_beep:
            cmd_str = ":SYSTem:BEEPer:STATe %d"%is_beep[s]
            if not(s in cmd_dict):
                cmd_dict[s]= []
            cmd_dict[s].append(cmd_str)
    """
    print(cmd_dict)
    universalcom(cmd_dict)


def _initcmddict(Bias, Step, Sweep, Open, Common):
    if Common.get("smu_info"): return
    addr_dict = {}
    smu_info = {}
    cmd_dict = {}
    smu_list = Open.keys() + Bias.keys() + Step.keys() + Sweep.keys()
    for s in smu_list:
        addr = inst.getaddress(s)
        ch = inst.getinstattr(s, "channel")
        if addr not in addr_dict:
            addr_dict[addr] = s  # get communication SMU
            smu_info[s] = [s, ch]
            cmd_dict[s] = []
        else:
            smu_info[s] = [addr_dict[addr], ch]
    for s in Open: smu_info[s].append(-1)
    for s in Bias: smu_info[s].append(Bias[s][1])
    for s in Step: smu_info[s].append(Step[s][1])
    for s in Sweep: smu_info[s].append(Sweep[s][1])
    # print("smu_info = ",smu_info,"cmd_dict=",cmd_dict)
    # smu_info = {'SMU2': ['SMU1', 2, 1], 'SMU1': ['SMU1', 1, 1]}
    # cmd_dict = {"SMU1":[],"SMU2":[]}
    Common["smu_info"] = smu_info
    Common["cmd_dict"] = cmd_dict


def checkcomp(Common):
    #    print("checkcomp",Common.get("stop_comp"))

    rval = OK
    if Common.get("stop_comp") == 0:
        return rval
    for s in Common["smu_info"]:
        cmd = ":sens%d:%s:prot:trip?" % (Common["smu_info"][s][1], Func_Map_R[Common["smu_info"][s][2]])
        val = universalcom({s: [cmd]}, 2)
        # val = universalcom({s:[":SENS:CURR:PROT:TRIP?"]},2)
        code = eval(val)
        if code == 1:
            rval = COMP_OCCURED
            return rval
    return rval


def init(Bias, Step, Sweep, Open, Meas_Range, Src_Range, Compliance, Remote_Sense, Meas_Seq, Meas_Pro, Common):
    ## Create cmd list to save communication time
    _initcmddict(Bias, Step, Sweep, Open, Common)
    for csmu in Common["cmd_dict"]:  # reset will act on both channels.
        Common["cmd_dict"][csmu].append("*rst")
    universalcom(Common["cmd_dict"])


def setup(Bias, Step, Sweep, Open, Meas_Range, Src_Range, Compliance, Remote_Sense, Meas_Seq, Meas_Pro, Common):
    ## Create cmd list to save communication time
    _initcmddict(Bias, Step, Sweep, Open, Common)
    # return
    for s in Src_Range:
        csmu = Common["smu_info"][s][0]
        ch = Common["smu_info"][s][1]
        func_str = Func_Map[Src_Range[s][2]]
        cmd_str = ":sour%d:func:mode %s" % (ch, func_str)
        Common["cmd_dict"][csmu].append(cmd_str)
        if Src_Range[s][0] == 1:  # fixed range
            cmd_str = ":sour%d:%s:rang:auto 0;:sour%d:%s:rang %g" % (ch, func_str, ch, func_str, Src_Range[s][1])
        elif Src_Range[s][0] == 2:  # auto range with low limit
            cmd_str = ":sour%d:%s:rang:auto 1;:sour%d:%s:rang:auto:llim %g" % (
                ch, func_str, ch, func_str, Src_Range[s][1])
        else:  # auto range
            cmd_str = ":sour%d:%s:rang:auto 1" % (ch, func_str)
        Common["cmd_dict"][csmu].append(cmd_str)
    for s in Meas_Seq:
        csmu = Common["smu_info"][s][0]
        ch = Common["smu_info"][s][1]
        func_id = Meas_Seq[s][0]
        func_str = ["\"curr\"", "\"volt\"", "\"curr\",\"volt\""][func_id]
        cmd_str = ":sens%d:func %s" % (ch, func_str)
        Common["cmd_dict"][csmu].append(cmd_str)
    for s in Meas_Range:
        csmu = Common["smu_info"][s][0]
        ch = Common["smu_info"][s][1]
        func_str = Func_Map[Meas_Range[s][2]]
        if Meas_Range[s][0] == 1:  # fixed range
            cmd_str = ":sens%d:%s:rang:auto 0;:sens%d:%s:rang %g" % (ch, func_str, ch, func_str, Meas_Range[s][1])
        elif Meas_Range[s][0] == 2:  # auto range with low limit
            cmd_str = ":sens%d:%s:rang:auto 1;:sens%d:%s:rang:auto:llim %g" % (
                ch, func_str, ch, func_str, Meas_Range[s][1])
        else:  # auto range
            cmd_str = ":sens%d:%s:rang:auto 1" % (ch, func_str)
        Common["cmd_dict"][csmu].append(cmd_str)
        # set plc
        cmd_str = ":sens%d:%s:nplc %g" % (ch, func_str, Common["NPLC"])
        Common["cmd_dict"][csmu].append(cmd_str)
    for s in Compliance:
        csmu = Common["smu_info"][s][0]
        cmd_str = ":sens%d:%s:prot %g" % (Common["smu_info"][s][1], Func_Map[Compliance[s][1]], Compliance[s][0])
        Common["cmd_dict"][csmu].append(cmd_str)
    for s in Remote_Sense:
        csmu = Common["smu_info"][s][0]
        if Remote_Sense[s] != -1:
            cmd_str = ":sens%d:rem %d" % (Common["smu_info"][s][1], Remote_Sense[s])
            Common["cmd_dict"][csmu].append(cmd_str)
    for s in Open:
        csmu = Common["smu_info"][s][0]
        ch = Common["smu_info"][s][1]
        cmd_str = ":outp%d:off:mode hiz" % ch
        Common["cmd_dict"][csmu].append(cmd_str)
    # Calc Step value
    for s in Step:
        Step[s][0].append((Step[s][0][1] * 1.0 - Step[s][0][0]) / (Common["step_pts"] - 1))
    # send cmd
    universalcom(Common["cmd_dict"])


def universalcom(cmd_dict, func_id=0):
    """
    func_id: 0="write",1="read",2="ask",3="ask for values"
    """
    rval = None
    if not debug_mode:
        for s in cmd_dict:
            #            print(cmd_dict)
            cmd_str = ";".join(cmd_dict[s])
            for cmd_str in cmd_dict[s]:
                if func_id == 0:
                    inst.write(s, cmd_str)
                elif func_id == 1:
                    rval = inst.read(s)
                elif func_id == 2:
                    rval = inst.ask(s, cmd_str)
                elif func_id == 3:

                    rval = inst.ask_for_values(s, cmd_str)
                    while rval.count(9.91e37) > 0:
                        rval.remove(9.91e37)
            cmd_dict[s] = []  # clear cmd dict
    else:
        for s in cmd_dict:
            for cmd in cmd_dict[s]:
                print("\n ", s, cmd)
                if func_id == 0:
                    inst.write(s, cmd)
                elif func_id == 1:
                    rval = inst.read(s)
                elif func_id == 2:
                    rval = inst.ask(s, cmd)
                elif func_id == 3:
                    rval = inst.ask_for_values(s, cmd)
                    while rval.count(9.91e37) > 0:
                        rval.remove(9.91e37)
                print("\t", rval)
                err = inst.ask(s, ":syst:err:all?")
                print("error: ", err)
            cmd_dict[s] = []  # clear cmd dict
    return rval


def biassrc(Bias, Common, pts):
    """
        Set bias source
    """
    for s in Bias:
        csmu = Common["smu_info"][s][0]
        ch = Common["smu_info"][s][1]
        func = Func_Map[Bias[s][1]]
        cmd_str = ":sour%d:%s %.7g" % (ch, func, Bias[s][0])
        Common["cmd_dict"][csmu].append(cmd_str)
        Common["data_pro"][s].extend([Bias[s][0]] * pts)
    # send cmd
    universalcom(Common["cmd_dict"])


def outputonoff(Common, SMUs, on_off):
    onoff_str = ["off", "on"]
    # print("****outputonoff SMUs",SMUs)
    if on_off == 0:
        for s in Common["smu_info"]:
            csmu = Common["smu_info"][s][0]
            ch = Common["smu_info"][s][1]
            if Common["smu_info"][s] == 1:
                cmd_str = ":sour%d:volt 0" % ch
            else:
                cmd_str = ":sour%d:func:mode volt;:sour%d:volt 0" % (ch, ch)
            Common["cmd_dict"][csmu].append(cmd_str)
    if on_off == 1:  # set level 0 before output on
        for s in Common["smu_info"]:
            csmu = Common["smu_info"][s][0]
            ch = Common["smu_info"][s][1]
            func = Func_Map[Common["smu_info"][s][2]]
            cmd_str = ":sour%d:%s 0" % (ch, func)
            Common["cmd_dict"][csmu].append(cmd_str)
    for s in SMUs:
        csmu = Common["smu_info"][s][0]
        ch = Common["smu_info"][s][1]
        if on_off == 1:
            obj = inst.getinstobj(s)
            if obj.setting.get("on_off", 0) == 0:
                cmd_str = ":outp%d %s" % (ch, onoff_str[on_off])
                Common["cmd_dict"][csmu].append(cmd_str)
                obj.setting["on_off"] = 1
    universalcom(Common["cmd_dict"])


def starttrig(Common, trig_smuch):
    """
    cmd_str = ":trac1:cle;:trac2:cle;:trac:poin 100;:trac2:poin 100;:trac1:feed sens;:trac2:feed sens;:trac1:feed:cont next;:trac2:feed:cont next"
    inst.write("SMU1", cmd_str)
    print(cmd_str)
    rval = inst.ask("SMU1", ":SYST:ERR:ALL?")
    print("error:", rval)
    """
    for s in trig_smuch:
        cmd_str = ":init (@%s)" % (str(trig_smuch[s])[1:-1])
        Common["cmd_dict"][s].append(cmd_str)
    universalcom(Common["cmd_dict"])


def getpostdatainfo(SMUs, Meas_Seq, Meas_Pro, Common, step_ind):
    postdatainfo_dict = {}
    func_str = {}
    cnt_perpts = {}
    key_info = {}
    func_str["has_t"] = ["curr,time", "volt,time", "curr,volt,time", "time,"]
    cnt_perpts["has_t"] = [2, 2, 3, 1]
    if Common["step_pts"] > 1:
        key_info["has_t"] = [["I", "T_withi"], ["V", "T_withi"], ["V", "I", "T_withi"], ["T_withi"]]
    else:
        key_info["has_t"] = [["I", "T"], ["V", "T"], ["V", "I", "T"], ["T"]]
    func_str["no_t"] = ["curr", "volt", "curr,volt", ""]
    cnt_perpts["no_t"] = [1, 1, 2, 0]
    key_info["no_t"] = [["I"], ["V"], ["V", "I"], []]
    tmp = []
    if Common["gs_flag"] == 1:
        section_pts = Common["swp_pts"]
    else:
        section_pts = Common["sample_pts"]

    for i, s in enumerate(Meas_Seq.keys()):
        csmu = Common["smu_info"][s][0]
        ch = Common["smu_info"][s][1]
        func_id = Meas_Seq[s][0]
        if i == 0 and Common["time_stamp"] == 1:
            k = "has_t"
            Common["smu_t"] = s
        else:
            k = "no_t"
        cnt = cnt_perpts[k][func_id]
        if s in Meas_Pro:  # meas and pro
            cmd_str = ":form:elem:sens %s,sour;:sens%d:data?" % (func_str[k][func_id], ch)
            # key_info[k][func_id].append("S")
            tmp.append(s)
            postdatainfo_dict[s] = (
                csmu, cmd_str, cnt + 1, key_info[k][func_id] + ["S"], Meas_Seq[s][1], Meas_Pro[s], section_pts,
                Common["t_offset"])
        else:  # only meas
            # cmd_str = ":fetc:arr:%s? (@%d)"%(func_str[func_id],ch)
            cmd_str = ":form:elem:sens %s;:sens%d:data?" % (func_str[k][func_id], ch)
            postdatainfo_dict[s] = (
                csmu, cmd_str, cnt, key_info[k][func_id], Meas_Seq[s][1], [], section_pts, Common["t_offset"])
    prodata_dict = {}
    for s in set(Meas_Pro.keys()) - set(tmp):  # only source
        if s in Common["bias_nontrig"]:  # not triggered channel, for loopmode=0,1
            prodata_dict[s] = (None, None, 1, ["S"], [], Meas_Pro[s], section_pts)
        else:
            csmu = Common["smu_info"][s][0]
            ch = Common["smu_info"][s][1]
            k = "no_t"
            # key_info[k][3].append("S")
            cmd_str = ":form:elem:sens %ssour;:sens%d:data?" % (func_str[k][3], ch)
            postdatainfo_dict[s] = (
                csmu, cmd_str, cnt_perpts[k][3] + 1, key_info[k][3] + ["S"], [], Meas_Pro[s], section_pts,
                Common["t_offset"])
    # print("!!!!postdatainfo_dict",postdatainfo_dict)
    return postdatainfo_dict, prodata_dict


def getdatacheckcomp(SMUs, Meas_Seq, Meas_Pro, Common, step_ind):
    # real time post data every 0.05
    global cmd_dict
    if Common["delay_time"] > 0.05:
        get_int = Common["delay_time"]
    else:
        get_int = 0.05
    tripfunc_str = ["volt", "curr"]
    abort_flag = 0
    fetccmd_dict, prodata_dict = getpostdatainfo(SMUs, Meas_Seq, Meas_Pro, Common, step_ind)
    finish_cnt = 0
    rcv_cnt = {}
    result = {}
    for s in fetccmd_dict:
        rcv_cnt[s] = 0
        result[s] = {"V": [], "I": [], "T": [], "S": []}
    for s in prodata_dict:
        result[s] = {"S": []}

    if not fetccmd_dict.keys():
        return
    ref_s = fetccmd_dict.keys()[0]
    last_cnt = {}
    curr_cnt = {}
    t_last = time.clock()
    # for i in range(10):
    while 1:
        # check compliance
        if Common["stop_comp"] == 1:
            for s in SMUs:
                csmu = Common["smu_info"][s][0]
                ch = Common["smu_info"][s][1]
                func = tripfunc_str[Common["smu_info"][s][2]]
                cmd_dict = {csmu: [":sens%d:%s:prot:trip?" % (ch, func)]}
                rval = universalcom(cmd_dict, 3)
                if rval[0] == 1:
                    abort_flag = 1
                    aborttest(Common)
        #        print(222222,fetccmd_dict)
        for s in fetccmd_dict:
            cmd_dict = {fetccmd_dict[s][0]: [fetccmd_dict[s][1] + " %d" % rcv_cnt[s]]}
            rval = universalcom(cmd_dict, 3)
            last_cnt[s] = rcv_cnt[s]
            rcv_cnt[s] += len(rval) / fetccmd_dict[s][2]
            curr_cnt[s] = len(rval) / fetccmd_dict[s][2]
            if rcv_cnt[s] == Common["trig_cnt"]:
                finish_cnt += 1
            # parse data and post
            postdata(rval, fetccmd_dict[s], last_cnt[s], curr_cnt[s], result[s], step_ind, Common["t_offset"],
                     Common.get("is_postdata", 1))
        for s in prodata_dict:
            pro_data = Common["data_pro"][s]
            postdata(pro_data[last_cnt[ref_s]:(last_cnt[ref_s] + curr_cnt[ref_s])], prodata_dict[s], last_cnt[ref_s],
                     curr_cnt[ref_s], result[s], step_ind, Common["t_offset"], Common.get("is_postdata", 1))
        if abort_flag == 1: break
        if finish_cnt >= len(fetccmd_dict): break
        t_pass = time.clock() - t_last
        if t_pass < get_int:
            time.sleep(get_int - t_pass)
        t_last = time.clock()
        # time.sleep(0.5)
    if Common.get("smu_t", ''):  # for loop_mode = 1
        Common["t_offset"] = result[Common["smu_t"]]["T"][-1]
    for s in fetccmd_dict:  # confirm if test completed
        csmu = Common["smu_info"][s][0]
        cmd_dict[csmu] = ["*opc?"]
    rval = universalcom(cmd_dict, 2)
    # print("####",result)
    return result


def postdata(raw_data, data_info, last_cnt, curr_cnt, result, step_ind, t_offset, is_post):
    if type(raw_data) == type(1) or type(raw_data) == type(1.0):
        raw_data = [raw_data]
    if len(raw_data) == 0:
        return
    #    print("@@@ call postdata raw_data",raw_data)
    #    print("data_info",data_info)
    #    print("last_cnt",last_cnt)
    #    print("curr_cnt",curr_cnt)
    #    print("result",result)
    #    print("step_ind",step_ind)
    #    print("t_offset",t_offset)
    items = data_info[3]  # ["V","I","T"]
    offset = data_info[2]  # 3
    meas_name = data_info[4]
    pro_name = data_info[5]
    swp_pts = data_info[6]
    len_raw = curr_cnt
    len_last = last_cnt
    sep = []
    start = 0
    if step_ind == -1:
        stepi_start = (len_last + 1) / swp_pts
        tmp = divmod((len_last + len_raw), swp_pts)
        if tmp[1] > 0:
            stepi_end = tmp[0] + 1
        else:
            stepi_end = tmp[0]
    else:
        stepi_start = step_ind
        stepi_end = step_ind + 1

    # 2013-08-24 to make bias post data work.
    if stepi_start == stepi_end and stepi_end == 1:
        stepi_start = 0

    for i in range(stepi_start, stepi_end):
        if len_raw + len_last >= (i + 1) * swp_pts:
            end = (i + 1) * swp_pts - len_last
        else:
            end = len_raw
        sep.append((i, start, end))
        start = end
    # print("$$$$$$$$$$$",sep)
    if len(meas_name) > 0:
        if items.count("V") > 0 and items.count("I") > 0:
            V = [raw_data[i * offset] for i in range(len_raw)]
            I = [raw_data[i * offset + 1] for i in range(len_raw)]
            if is_post == 1:
                for i in sep:
                    __postdata(meas_name[i[0] * 2], V[i[1]:i[2]])
                    __postdata(meas_name[i[0] * 2 + 1], I[i[1]:i[2]])
            result["V"].extend(V)
            result["I"].extend(I)
        else:
            k = items[0]
            V_or_I = [raw_data[i * offset] for i in range(len_raw)]
            if is_post == 1:
                for i in sep:
                    __postdata(meas_name[i[0]], V_or_I[i[1]:i[2]])
            result[k].extend(V_or_I)
    if "T" in items:
        ind = items.index("T")
        T = [raw_data[i * offset + ind] + t_offset for i in range(len_raw)]
        if is_post == 1:
            for i in sep:
                __postdata("Time", T[i[1]:i[2]])
        result["T"].extend(T)
    elif "T_withi" in items:
        ind = items.index("T_withi")
        T = [raw_data[i * offset + ind] + t_offset for i in range(len_raw)]
        if is_post == 1:
            for i in sep:
                __postdata("Time(%d)" % (i[0] + 1), T[i[1]:i[2]])
        result["T"].extend(T)
    if "S" in items:
        ind = items.index("S")
        S = [raw_data[i * offset + ind] for i in range(len_raw)]
        if is_post == 1:
            for i in sep:
                __postdata(pro_name[i[0]], S[i[1]:i[2]])
        result["S"].extend(S)


def __postdata(name, val_list):
    # postarraydata(name, val_list)
    pass
    # print("***in B2900A module",name, str(val_list))


def aborttest(Common):
    for s in Common["trig_smuch"]:
        csmu = Common["smu_info"][s][0]
        chs = Common["trig_smuch"][s]
        cmd_str = ":abor (@%s)" % (",".join(chs))
        Common["cmd_dict"][csmu].append(cmd_str)
        inst.write(s, cmd_str)
    for s in Common["nontrig_smu"]:
        csmu = Common["smu_info"][s][0]
        ch = Common["smu_info"][s][1]
        func = Func_Map[Common["smu_info"][s][2]]
        cmd_str = ":sour%d:%s 0" % (ch, func)
        Common["cmd_dict"][csmu].append(cmd_str)
    universalcom(Common["cmd_dict"])


def srcmeassample(Bias, Open, Meas_Range, Src_Range, Compliance, Remote_Sense, Meas_Seq, Meas_Pro, Common):
    ############for Test################
    #     __postdata('ivy',[1,2,3,4,5])
    #    return
    Common["data_pro"] = {}
    Common["t_offset"] = 0
    Common["bias_nontrig"] = []
    loop_mode = 0
    is_srcrngfix = [0 for s in Src_Range if Src_Range[s][0] != 1]
    is_measrngfix = [0 for s in Meas_Range if Meas_Range[s][0] != 1]
    result = {}
    if Common.get("stop_comp") == 1:
        loop_mode = 2
    elif Common["sample_pts"] == 1:
        loop_mode = 2  # spot test
    elif len(is_srcrngfix) > 0 or len(is_measrngfix) > 0:
        loop_mode = 2
    else:
        csmu_list = [Common["smu_info"][s][0] for s in Meas_Seq.keys()]
        if len(csmu_list) > 1: loop_mode = 2
    if loop_mode == 2:  # non trigger mode
        for s in Bias.keys():
            Common["data_pro"][s] = []
        # source-measure loop
        # calc step value for sweep
        outputonoff(Common, Bias.keys(), 1)
        result = srcmeasloop({}, {}, Bias, Compliance, Meas_Seq, Meas_Pro, Common)
        outputonoff(Common, Bias.keys(), 0)
    else:  # trigger mode
        Common["bias_nontrig"] = list(set(Bias.keys()) - set(Meas_Seq.keys()))
        sampletrigsetup(Bias, Meas_Seq, Meas_Pro, Src_Range, Common)
        tmp_bias = {}
        for s in Bias:
            Common["data_pro"][s] = []
            tmp_bias[s] = Bias[s]
        # biassrc(tmp_bias, Common, Common["sample_pts"])
        biassrc(Bias, Common, Common["sample_pts"])
        outputonoff(Common, Bias.keys(), 1)
        starttrig(Common, Common["trig_smuch"])
        result = getdatacheckcomp(Bias.keys(), Meas_Seq, Meas_Pro, Common, -1)
        outputonoff(Common, Bias.keys(), 0)
    return result


def srcmeas(Sweep, Step, Bias, Open, Meas_Range, Src_Range, Compliance, Remote_Sense, Meas_Seq, Meas_Pro, Common):
    global nontrig_bias
    loop_mode = 0
    result = {}
    is_srcrngfix = [0 for s in Src_Range if Src_Range[s][0] != 1]
    is_measrngfix = [0 for s in Meas_Range if Meas_Range[s][0] != 1]
    Common["bias_nontrig"] = []
    Common["data_pro"] = {}
    Common["t_offset"] = 0
    if Common["stop_comp"] == 1:
        loop_mode = 2
    elif Common["gs_flag"] == 0 and Common["sample_pts"] == 1:
        loop_mode = 2  # spot test
    elif len(is_srcrngfix) > 0 or len(is_measrngfix) > 0:
        loop_mode = 2
    else:
        swpmeas_smu = list(set(Sweep.keys() + Meas_Seq.keys()))
        nontrig_bias = []
        csmu_list = [Common["smu_info"][s][0] for s in swpmeas_smu]
        csmu_list = list(set(csmu_list))
        if len(csmu_list) > 1:
            loop_mode = 2
        elif len(Step) > 1:
            loop_mode = 2
        else:
            ref_csmu = csmu_list[0]
            for s in Step:
                csmu = Common["smu_info"][s][0]
                if csmu != ref_csmu:
                    loop_mode = 1
                    nontrig_bias.append(s)
            for s in Bias:
                csmu = Common["smu_info"][s][0]
                if csmu != ref_csmu:
                    nontrig_bias.append(s)
            Common["bias_nontrig"] = nontrig_bias
    # loop_mode = 1
    # print("****loop_mode", loop_mode)
    if loop_mode == 2:
        for s in Bias.keys() + Step.keys() + Sweep.keys():
            Common["data_pro"][s] = []
        # source-measure loop
        # calc step value for sweep
        for s in Sweep:
            s_param = Sweep[s][0]
            # get step val
            if s_param[0] == 0:  # linear mode
                s_param.append((s_param[-1] * 1.0 - s_param[-2]) / (Common["swp_pts"] - 1))
            elif s_param[0] == 1:  # myLog mode
                s_param.append((math.log10(abs(s_param[-1])) - math.log10(abs(s_param[-2]))) / (Common["swp_pts"] - 1))
        outputonoff(Common, Bias.keys() + Step.keys() + Sweep.keys(), 1)
        result = srcmeasloop(Sweep, Step, Bias, Compliance, Meas_Seq, Meas_Pro, Common)
        outputonoff(Common, Bias.keys() + Step.keys() + Sweep.keys(), 0)
    else:  # use trigger mode
        sweepmeastrigsetup(Sweep, Step, Bias, Meas_Seq, Meas_Pro, Src_Range, Common)
        # return
        if loop_mode == 0:
            tmp_bias = {}
            for s in nontrig_bias:
                Common["data_pro"][s] = []
                tmp_bias[s] = Bias[s]
            biassrc(tmp_bias, Common, Common["swp_pts"] * Common["step_pts"])
            outputonoff(Common, Bias.keys() + Step.keys() + Sweep.keys(), 1)
            starttrig(Common, Common["trig_smuch"])
            result = getdatacheckcomp(Bias.keys() + Sweep.keys() + Step.keys(), Meas_Seq, Meas_Pro, Common, -1)
            outputonoff(Common, Sweep.keys() + Step.keys() + Bias.keys(), 0)
        else:
            # trig_smu = list(set(Sweep.keys()+Bias.keys()+Step.keys())-set(Common["bias_nontrig"]))
            for i in range(Common["step_pts"]):
                tmp_bias = {}
                rst_bias = {}
                for s in nontrig_bias:
                    Common["data_pro"][s] = []
                    if s in Step:
                        tmp_bias[s] = (Step[s][0][0] + i * Step[s][0][2], Step[s][1])
                        rst_bias[s] = (0, Step[s][1])
                    else:
                        tmp_bias[s] = Bias[s]
                        rst_bias[s] = (0, Bias[s][1])
                biassrc(tmp_bias, Common, Common["swp_pts"])
                if i == 0:
                    outputonoff(Common, Bias.keys() + Step.keys() + Sweep.keys(), 1)
                starttrig(Common, Common["trig_smuch"])
                result = getdatacheckcomp(Bias.keys() + Sweep.keys() + Step.keys(), Meas_Seq, Meas_Pro, Common, i)
                biassrc(rst_bias, Common, 1)
            outputonoff(Common, Sweep.keys() + Step.keys() + Bias.keys(), 0)
    #    print("##### result",result)

    #    i_val = result["SMU1"]["I"]
    #    v_val = result["SMU1"]["V"]
    #    diff_1 = util.mathlib.DIFF(v_val, i_val)
    #    diff = util.mathlib.DIFF(v_val, diff_1)
    #    pos = util.mathlib.MAXPOS(util.mathlib.ABS(diff))
    #    pos = util.mathlib.FINDLIN(i_val, -0.0001, 0)
    #    vbr = util.mathlib.AT(v_val, pos)
    #    ibr = util.mathlib.AT(i_val, pos)
    # vbr = v_val[pos]
    # ibr = i_val[pos]
    #    __postdata("Vbr", [vbr])
    #    __postdata("Ibr", [ibr])
    if Common.get("is_returndata", 0) == 1:
        return result
    else:
        return 0


def srcmeasloop(Sweep, Step, Bias, Compliance, Meas_Seq, Meas_Pro, Common):
    # fetccmd_dict[s] = (csmu, cmd_str,cnt+1,data_info[k][func_id], Meas_Seq[s][1],Meas_Pro[s],Common["swp_pts"],Common["t_offset"])
    comp_occured = OK
    result = {}
    SMUs = Sweep.keys() + Step.keys() + Bias.keys()
    raw_data = {}
    for s in SMUs:
        result[s] = {"V": [], "I": [], "T": [], "S": []}
    rval = getpostdatainfo(SMUs, Meas_Seq, Meas_Pro, Common, -1)
    postdata_info = rval[0]
    t_start = time.clock()
    biassrc(Bias, Common, 1)
    if Common["gs_flag"] == 0:
        for i in range(Common["sample_pts"]):
            # check compliance
            comp_occured = checkcomp(Common)
            # print("comp_occured",comp_occured)
            if comp_occured != COMP_OCCURED:
                if i == 0:
                    time.sleep(Common["hold_time"])
                time.sleep(Common["delay_time"])
            t_post = time.clock() - t_start
            rval = spotmeas(Meas_Seq, Common, Compliance, comp_occured)
            for s in postdata_info:
                raw_data = rval.get(s, [])
                if "T" in postdata_info[s][3]:
                    raw_data.append(t_post)
                if "S" in postdata_info[s][3]:
                    raw_data.append(Common["data_pro"][s][-1])
                postdata(raw_data, postdata_info[s], 0, 1, result[s], -1, 0, Common.get("is_postdata", 1))
            if comp_occured == COMP_OCCURED:
                return result
    else:
        for i in range(Common["step_pts"]):
            tmp_bias = {}
            for s in Step:
                tmp_bias[s] = (Step[s][0][0] + i * Step[s][0][2], Step[s][1])
            biassrc(tmp_bias, Common, 1)
            for j in range(Common["swp_pts"]):
                tmp_bias = {}
                for s in Sweep:
                    s_param = Sweep[s][0]
                    if s_param[0] == 0:
                        tmp_bias[s] = (s_param[-3] + j * s_param[-1], Sweep[s][1])
                    elif s_param[0] == 1:  # myLog mode
                        tmp_bias[s] = (s_param[-3] * 10 ** (s_param[-1] * j), Sweep[s][1])
                    else:  # list mode
                        tmp_bias[s] = (s_param[1 + j], Sweep[s][1])
                biassrc(tmp_bias, Common, 1)
                # check compliance
                comp_occured = checkcomp(Common)
                if comp_occured != COMP_OCCURED:
                    if i == 0 and j == 0:
                        time.sleep(Common["hold_time"])
                    time.sleep(Common["delay_time"])
                # meas
                t_post = time.clock() - t_start
                rval = spotmeas(Meas_Seq, Common, Compliance, comp_occured)
                for s in postdata_info:
                    raw_data = rval.get(s, [])
                    if "T" in postdata_info[s][3] or "T_withi" in postdata_info[s][3]:
                        raw_data.append(t_post)
                    if "S" in postdata_info[s][3]:
                        raw_data.append(Common["data_pro"][s][-1])
                    postdata(raw_data, postdata_info[s], 0, 1, result[s], i, 0, Common.get("is_postdata", 1))
                if comp_occured == COMP_OCCURED:
                    return result
    return result


def spotmeas(Meas_Seq, Common, Compliance, comp_occured):
    func_str = ["curr", "volt", "curr,volt"]
    rval = {}
    for s in Meas_Seq:
        csmu = Common["smu_info"][s][0]
        func_id = Meas_Seq[s][0]
        func = func_str[Meas_Seq[s][0]]
        ch = Common["smu_info"][s][1]
        rval[s] = universalcom({csmu: [":form:elem:sens %s;:meas? (@%d)" % (func, ch)]}, 3)
        if comp_occured == COMP_OCCURED:
            # Overwrite 9.9e37 by compliance value
            if Compliance[s][1] == 0 and (func_id == 0 or func_id == 2) and abs(rval[s][-1]) == 9.9e37:
                rval[s][-1] = Compliance[s][0]
            if Compliance[s][1] == 1 and (func_id == 1 or func_id == 2) and abs(rval[s][0]) == 9.9e37:
                rval[s][0] = Compliance[s][0]
    return rval


def sampletrigsetup(Bias, Meas_Seq, Meas_Pro, Src_Range, Common):
    global csmu
    meas_t = Common["NPLC"] * 0.02  # 20ms/1PLC
    trig_ch = []
    if Meas_Seq.keys():
        for s in Meas_Seq.keys():
            csmu = Common["smu_info"][s][0]
            ch = Common["smu_info"][s][1]
            trig_ch.append(ch)
            cmd_str = ":arm%d:sour aint;:arm%d:tran:del %g" % (ch, ch, Common["hold_time"])
            Common["cmd_dict"][csmu].append(cmd_str)
            cmd_str = ":trig%d:sour tim;:trig%d:tim %g;:trig%d:coun %d;:trig%d:acq:del %g" % (
                ch, ch, Common["delay_time"] + meas_t, ch, Common["sample_pts"], ch, Common["delay_time"])
            Common["cmd_dict"][csmu].append(cmd_str)
        Common["trig_smuch"] = {csmu: trig_ch}
        Common["trig_cnt"] = Common["sample_pts"]
        # send cmd
        universalcom(Common["cmd_dict"])


def sweepmeastrigsetup(Sweep, Step, Bias, Meas_Seq, Meas_Pro, Src_Range, Common):
    """
    Sweep and Measure SMU channel must be in the same B2900 rack.
    If test only uses one B2900, step or bias will be implemented by list.
    """
    src_smu = []
    trig_cnt = 0
    trig_csmu = ""
    trig_ch = []
    # setup source
    for s in Sweep:
        src_smu.append(s)
        trig_cnt = Common["swp_pts"]
        csmu = Common["smu_info"][s][0]
        ch = Common["smu_info"][s][1]
        trig_csmu = csmu
        trig_ch.append(ch)
        func = Func_Map[Sweep[s][1]]
        swp_param = Sweep[s][0]
        lin_log = ("lin", "myLog")[swp_param[0]]
        if swp_param[0] < 2:  # sweep
            # setup swp range
            cmd_str = ":sour%d:swe:rang %s" % (ch, ("auto", "fix", "best")[Src_Range[s][0]])
            Common["cmd_dict"][csmu].append(cmd_str)
            cmd_str = ":sour%d:%s:mode swe;:swe:spac %s;:%s:star %g;:%s:stop %g;:%s:poin %d" % (
                ch, func, lin_log, func, swp_param[1], func, swp_param[2], func, Common["swp_pts"])
            Common["cmd_dict"][csmu].append(cmd_str)
        else:  # list mode
            cmd_str = ":sour%d:%s:mode list;:list:%s %s" % (ch, func, func, ",".join(swp_param[1:]))
            Common["swp_pts"] = len(swp_param) - 1
            Common["cmd_dict"][csmu].append(cmd_str)
    step_trig = list(set(Step.keys()) - set(Common["bias_nontrig"]))
    for s in step_trig:
        src_smu.append(s)
        trig_cnt = Common["swp_pts"] * Common["step_pts"]
        csmu = Common["smu_info"][s][0]
        ch = Common["smu_info"][s][1]
        trig_ch.append(ch)
        trig_csmu = csmu
        func = Func_Map[Step[s][1]]
        step_param = Step[s][0]
        step_step = (step_param[1] - step_param[0]) / (Common["step_pts"] - 1) * 1.0
        step_val = [step_param[0]] * Common["swp_pts"]
        for i in range(1, Common["step_pts"]):
            step_val.extend([step_param[0] + i * step_step] * Common["swp_pts"])
        # print(step_val)
        cmd_str = ":sour%d:%s:mode list;:sour%d:list:%s %s" % (ch, func, ch, func, str(step_val)[1:-1])
        Common["cmd_dict"][csmu].append(cmd_str)
    bias_trig = list(set(Bias.keys()) - set(Common["bias_nontrig"]))
    for s in bias_trig:
        src_smu.append(s)
        trig_cnt = Common["swp_pts"]
        csmu = Common["smu_info"][s][0]
        ch = Common["smu_info"][s][1]
        trig_csmu = csmu
        trig_ch.append(ch)
        func = Func_Map[Bias[s][1]]
        bias_val = [Bias[s][0]] * Common["swp_pts"]
        cmd_str = ":sour%d:%s:mode list;:sour%d:list:%s %s" % (ch, func, ch, func, str(bias_val)[1:-1])
        Common["cmd_dict"][csmu].append(cmd_str)
    # setup trigger
    Common["trig_cnt"] = trig_cnt
    for s in Sweep.keys() + step_trig + bias_trig:
        csmu = Common["smu_info"][s][0]
        ch = Common["smu_info"][s][1]
        cmd_str = ":arm%d:sour aint;:arm%d:tran:del %g" % (ch, ch, Common["hold_time"])
        Common["cmd_dict"][csmu].append(cmd_str)
        cmd_str = ":trig%d:sour aint;:trig%d:coun %d;:trig%d:acq:del %g" % (
            ch, ch, Common["trig_cnt"], ch, Common["delay_time"])
        Common["cmd_dict"][csmu].append(cmd_str)
    Common["trig_smuch"] = {trig_csmu: trig_ch}
    # send cmd
    universalcom(Common["cmd_dict"])
